package com.zxt.utils;

import lombok.extern.slf4j.Slf4j;

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.GeneralSecurityException;
import java.util.Base64;
import java.util.UUID;

@Slf4j
public class AesUtils {

    public static final String aesName = "AES";
    public static final String aesTransformation = "AES/CBC/PKCS5Padding";

    public static final int ENCRYPT_MODE = 1;

    public static final int DECRYPT_MODE = 2;


    public static void main(String[] args) {
        String aesKey = UUID.randomUUID().toString().replaceAll("-", "");
        String content = "123456789009876543";
        String encryption = encryption(content, aesKey);
        System.out.println("加密结果：" + encryption);
        String decrypt = decrypt(encryption, aesKey);
        System.out.println("解密结果：" + decrypt);
    }


    public static String encryption(String content, String aesKey) {
        return new String(Base64.getEncoder().encode((aesEncrypt(content.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(aesKey)))));
    }

    public static String decrypt(String content, String aesKey) {
        return new String(aesDecrypt(Base64.getDecoder().decode(content), Base64.getDecoder().decode(aesKey)));
    }


    /**
     * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
     *
     * @param input 原始字节数组
     * @param key   符合AES要求的密钥
     * @param iv    初始向量
     * @param mode  Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
     */
    private static byte[] aes(byte[] input, byte[] key, byte[] iv, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, aesName);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);
            Cipher cipher = Cipher.getInstance(aesTransformation);
            cipher.init(mode, secretKey, ivSpec);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }


    /**
     * 使用AES解密字符串, 返回原始字符串.
     *
     * @param input Hex编码的加密字符串
     * @param key   符合AES要求的密钥
     */
    private static byte[] aesDecrypt(byte[] input, byte[] key) {
        return aes(input, key, DECRYPT_MODE);
    }

    /**
     * 使用AES加密原始字符串.
     *
     * @param input 原始输入字符数组
     * @param key   符合AES要求的密钥
     */
    private static byte[] aesEncrypt(byte[] input, byte[] key) {
        return aes(input, key, ENCRYPT_MODE);
    }

    /**
     * 使用AES加密或解密无编码的原始字节数组, 返回无编码的字节数组结果.
     *
     * @param input 原始字节数组
     * @param key   符合AES要求的密钥
     * @param mode  Cipher.ENCRYPT_MODE 或 Cipher.DECRYPT_MODE
     */
    private static byte[] aes(byte[] input, byte[] key, int mode) {
        try {
            SecretKey secretKey = new SecretKeySpec(key, aesName);
            Cipher cipher = Cipher.getInstance(aesName);
            cipher.init(mode, secretKey);
            return cipher.doFinal(input);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }
    }
}
